// SPDX-License-Identifier: LGPL-2.1-only
/*
 * Author: Weijie Gao <hackpascal@gmail.com>
 *
 * ESMT SPI-NAND flash parts
 */

#include <stdio.h>
#include <string.h>
#include <ufprog/sizes.h>
#include "core.h"
#include "ecc.h"
#include "otp.h"

static struct nand_otp_info esmt_otp = {
	.start_index = NAND_OTP_PAGE_OTP,
	.count = 28,
};

static const struct nand_page_layout esmt_ecc_layout = ECC_PAGE_LAYOUT(
	ECC_PAGE_DATA_BYTES(2048),
	ECC_PAGE_MARKER_BYTES(1),
	ECC_PAGE_PARITY_BYTES(7),
	ECC_PAGE_OOB_DATA_BYTES(8),
	ECC_PAGE_UNUSED_BYTES(1),
	ECC_PAGE_PARITY_BYTES(7),
	ECC_PAGE_OOB_DATA_BYTES(8),
	ECC_PAGE_UNUSED_BYTES(1),
	ECC_PAGE_PARITY_BYTES(7),
	ECC_PAGE_OOB_DATA_BYTES(8),
	ECC_PAGE_UNUSED_BYTES(1),
	ECC_PAGE_PARITY_BYTES(7),
	ECC_PAGE_OOB_DATA_BYTES(8),
);

static DEFINE_SNAND_ALIAS(f50l1g41a_alias, SNAND_ALIAS_VENDOR_MODEL(&vendor_issi, "IS37SML01G1"),
					   SNAND_ALIAS_VENDOR_MODEL(&vendor_issi, "IS38SML01G1"));

static const struct spi_nand_flash_part esmt_parts[] = {
	SNAND_PART("F50L512M41A", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x20), &snand_memorg_512m_2k_64,
		   NAND_ECC_REQ(512, 1),
		   SNAND_FLAGS(SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_2 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(104),
		   SNAND_PAGE_LAYOUT(&esmt_ecc_layout),
	),

	SNAND_PART("F50L1G41A", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x21), &snand_memorg_1g_2k_64,
		   NAND_ECC_REQ(512, 1),
		   SNAND_ALIAS(&f50l1g41a_alias),
		   SNAND_FLAGS(SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_2 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(104),
		   SNAND_PAGE_LAYOUT(&esmt_ecc_layout),
	),

	SNAND_PART("F50L1G41LB", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x01), &snand_memorg_1g_2k_64,
		   NAND_ECC_REQ(512, 1),
		   SNAND_FLAGS(SNAND_F_GENERIC_UID | SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_X2 | BIT_SPI_MEM_IO_X4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(104),
		   SNAND_PAGE_LAYOUT(&ecc_2k_64_1bit_layout),
		   NAND_OTP_INFO(&esmt_otp),
	),

	SNAND_PART("F50D1G41LB", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x11), &snand_memorg_1g_2k_64, /* 1.8V */
		   NAND_ECC_REQ(512, 1),
		   SNAND_FLAGS(SNAND_F_GENERIC_UID | SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_X2 | BIT_SPI_MEM_IO_X4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(66),
		   SNAND_PAGE_LAYOUT(&ecc_2k_64_1bit_layout),
		   NAND_OTP_INFO(&esmt_otp),
	),

	SNAND_PART("F50L2G41LB", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x0a), &snand_memorg_2g_2k_64_2d,
		   NAND_ECC_REQ(512, 1),
		   SNAND_FLAGS(SNAND_F_GENERIC_UID | SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_X2 | BIT_SPI_MEM_IO_X4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(104),
		   SNAND_PAGE_LAYOUT(&ecc_2k_64_1bit_layout),
		   NAND_OTP_INFO(&esmt_otp),
	),

	SNAND_PART("F50D2G41LB", SNAND_ID(SNAND_ID_DUMMY, 0xc8, 0x1a), &snand_memorg_2g_2k_64_2d, /* 1.8V */
		   NAND_ECC_REQ(512, 1),
		   SNAND_FLAGS(SNAND_F_GENERIC_UID | SNAND_F_BBM_2ND_PAGE),
		   SNAND_QE_DONT_CARE, SNAND_ECC_CR_BIT4, SNAND_OTP_CR_BIT6,
		   SNAND_RD_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_X2 | BIT_SPI_MEM_IO_X4),
		   SNAND_PL_IO_CAPS(BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4),
		   SNAND_RD_OPCODES(default_rd_opcodes_4d),
		   SNAND_SPI_MAX_SPEED_MHZ(50),
		   SNAND_PAGE_LAYOUT(&ecc_2k_64_1bit_layout),
		   NAND_OTP_INFO(&esmt_otp),
	),
};

static ufprog_status esmt_part_fixup(struct spi_nand *snand, struct spi_nand_flash_part_blank *bp)
{
	spi_nand_blank_part_fill_default_opcodes(bp);

	bp->p.nops = bp->p.memorg->page_size / 512;

	return UFP_OK;
}

static const struct spi_nand_flash_part_fixup esmt_fixups = {
	.pre_param_setup = esmt_part_fixup,
};

static const struct spi_nand_flash_part_ops esmt_part_ops = {
	.select_die = spi_nand_select_die_c2h,
	.check_ecc = spi_nand_check_ecc_1bit_per_step,
};

static ufprog_status esmt_pp_post_init(struct spi_nand *snand, struct spi_nand_flash_part_blank *bp)
{
	bp->p.qe_type = QE_CR_BIT0;
	bp->p.ecc_type = ECC_CR_BIT4;
	bp->p.otp_en_type = OTP_CR_BIT6;

	bp->p.rd_io_caps = BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_2 | BIT_SPI_MEM_IO_1_1_4;
	bp->p.pl_io_caps = BIT_SPI_MEM_IO_1_1_1 | BIT_SPI_MEM_IO_1_1_4;

	return UFP_OK;
}

static const struct spi_nand_vendor_ops esmt_ops = {
	.pp_post_init = esmt_pp_post_init,
};

const struct spi_nand_vendor vendor_esmt = {
	.mfr_id = SNAND_VENDOR_GIGADEVICE,
	.id = "esmt",
	.name = "ESMT",
	.parts = esmt_parts,
	.nparts = ARRAY_SIZE(esmt_parts),
	.ops = &esmt_ops,
	.default_part_ops = &esmt_part_ops,
	.default_part_fixups = &esmt_fixups,
	.default_part_otp_ops = &spi_nand_otp_ops,
};
